package com.wchen.gdoc.generate.resource.analysis;

import com.sun.javadoc.*;
import com.wchen.gdoc.generate.config.ApplicationConfig;
import com.wchen.gdoc.generate.config.ApplicationConfigProvide;
import com.wchen.gdoc.generate.resource.structure.FieldStructure;
import com.wchen.gdoc.generate.util.StringUtil;

import java.util.*;


/**
 * 对象类型解析器
 *
 * @author  wchen
 * @date    2019/11/7
 */
public class ObjectTypeDocAnalysis extends AbsGenericAnalysis implements DocTypeAnalysis {
    private FieldTypeFilter fieldTypeFilter = new FieldTypeFilter();

    @Override
    public Boolean isSupport(Type docType) {
        ApplicationConfig applicationConfig = ApplicationConfigProvide.getApplicationConfig();
        String entityPackages = applicationConfig.getTargetProjectConfig().getTargetEntityPackage();
        String filterEntityStr = applicationConfig.getTargetProjectConfig().getFilterEntity();
        List<String> filterEntityList = Arrays.asList(filterEntityStr.split(";"));
        String docTypeName = docType.simpleTypeName();
        for (String entityPackage : entityPackages.split(";")) {
            if(StringUtil.isNotBlank(entityPackage) && docType.qualifiedTypeName().startsWith(entityPackage) && !filterEntityList.contains(docTypeName)){
                return true;
            }
        }

        return false;
    }

    @Override
    public FieldStructure analysisParam(Type docType, Boolean isRequestParam) {
        if(ENABLE_DEBUG) {
            LOGGER.info(String.format("execute ObjectTypeDocAnalysis, docType=%s", docType.qualifiedTypeName()));
        }
        //自定义过滤
        Set<String> configFields = matchDealFields(docType.qualifiedTypeName());
        //泛型映射获取
        super.extractGeneric(docType);
        FieldStructure objectTypeStructure = new FieldStructure();
        List<FieldStructure> fieldStructureList = new ArrayList<>();
        for (FieldDoc fieldDoc : docType.asClassDoc().fields(false)) {
            if(fieldTypeFilter.isFieldSkip(fieldDoc, isRequestParam)){
                continue;
            }

            //忽略自定义字段
            if(configFields.contains(fieldDoc.name())) {
                continue;
            }

            Type fieldDocType = calculateType(fieldDoc.type());
            FieldStructure fieldStructure = super.executeAnalysis(fieldDocType, isRequestParam);
            if (Objects.isNull(fieldStructure)){
                continue;
            }
            fieldStructure.setFieldCommentText(fieldDoc.commentText());
            fieldStructure.setType(fieldDoc.type().qualifiedTypeName());
            fieldStructure.setFieldName(fieldDoc.name());
            fieldStructure.setFieldAnnotationList(analysisAnnotationDoc(fieldDoc.annotations()));
            fieldStructureList.add(fieldStructure);
        }
        ClassDoc classDoc = docType.asClassDoc();
        objectTypeStructure.setFieldAnnotationList(analysisAnnotationDoc(classDoc.annotations()));
        objectTypeStructure.setFieldCommentText(classDoc.commentText());
        objectTypeStructure.setCommentText(classDoc.commentText());
        objectTypeStructure.setSimpleName(classDoc.simpleTypeName());
        objectTypeStructure.setType(classDoc.qualifiedTypeName());
        objectTypeStructure.setFieldList(fieldStructureList);

        super.removeTypeNode();
        return objectTypeStructure;
    }



    /**
     * 获取匹配的自定义过滤
     * @param classType
     * @return
     */
    private HashSet<String> matchDealFields(String classType) {
        Map<String, List<String>> exclusiveFieldMap = ApplicationConfigProvide.getApplicationConfig().getTargetProjectConfig().getExclusiveFieldMap();
        List<String> customList = exclusiveFieldMap.get(classType);

        return customList == null ? new HashSet<>() : new HashSet<String>(customList);
    }

    /**
     * 计算泛型最终类型
     *
     * @param docType
     * @return
     */
    @Override
    protected Type calculateType(Type docType) {
        //集合类型不处理
        // TODO: 2020/3/21 待优化逻辑
        List<DocTypeAnalysis> absParentAnalysisList = ApplicationConfigProvide.getApplicationConfig().getDocTypeAnalysisChain();
        for (DocTypeAnalysis docTypeAnalysis : absParentAnalysisList) {
            if(docTypeAnalysis instanceof ListTypeDocAnalysis){
                if(docTypeAnalysis.isSupport(docType)) {
                    return docType;
                }
            }
        }

        return super.calculateType(docType);
    }
}
